
#include <svc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aclconio.h>

// This module is intended as a prototype for application-initiated downloads.
// It extends the functionality of the OS-supported SVC_ZONTALK() call in
// several ways:
//
//     First, all FLASH files are cleared from the current group
//     Next, the FLASH file system is coalesced, and the system is restarted.
//     Finally, the actual download is initiated.
//
// The basic functionality provided here can be extended as needed for
// particular customer requirements.
//
// It is anticipated that this program will be loaded into group 15 FLASH,
// and will thus be available for use from any application group.
//
// It may be invoked from any group.  A parameter specifies the minimum
// amount of FLASH which must be recoverable in order to coalesce FLASH.
//
//     run ("F:/ApLoader.out", "20000");
//
// Beware!  In order for this program to run properly from any group EXCEPT
// group 1, the main application in group 1 must "cooperate" as stated below,
// by invoking the program in the subsidiary group's *GO parameter.  Otherwise,
// the program which invokes F:/ApLoader.out must first take the "appropriate"
// action to cause this program to be loaded from his group on the next restart.
//
// Normally this program will run TWICE.  The first time it runs it will remove
// all FLASH files in its own group: that is, in the group of the invoker.
// It then determines if a coalesce operation is needed.  The determination is
// based on the amount of space which can be recovered.  If a coalesce operation
// is justified, it invokes that operation, which causes the terminal to restart
// at the conclusion of the coalesce process.
//
// Now the interesting question becomes: how do we make this program run again,
// in order for it to invoke SVC_ZONTALK for the actual download?
//
// The answer given here is to set *GO to the name of this program.
//
// This simplistic approach works fine IF the program was invoked from group 1.
//
// On the other hand, if the program was NOT invoked from group 1, then
// programs in other groups must be invoked in some application-dependent
// manner.  It is possible that the application solution to this problem
// involves reading *GO in this group, in which case the program will work
// as written.  For other designs, the solution is left as an exercise....
//
// A final note: since this program "takes over" the group from which it is
// called, it will continue to run each time the terminal restarts.  On each
// restart it tries to invoke SVC_ZONTALK to obtain a full download for this
// group.  If the download is successful, the terminal will restart, and then
// the "real" application for this group will run instead of this program.
// On the other hand, if the download fails -- because of a phone line problem,
// for example -- then this program will try again.  And again, and again....

int txo_console;    // Keep the user informed about what we are doing
int sts;

long recover;        // Amount we can recover from coalescing
long minimum;        // Don't coalesce unless we can gain this many bytes,

const char* arg1 = "MIN";    // ...which the user specifies as an Ascii argument

char buffer[100];

char* szFlashStatus[4] = {
    "Preparing FLASH",
    "Preparing FLASH.",
    "Preparing FLASH..",
    "Preparing FLASH..."
};

int main(int argc,char* argv[]) {
    int loop = 1,
    Index = 0;

    if (argc > 1) {
        // Is this the initial invocation of the program?
        put_env("*GO", argv[0], strlen(argv[0]));   // Place me in charge
        put_env(arg1, argv[1], strlen(argv[1]));    // Save my minimum
    }

    SVC_WAIT(2000);

    txo_console = open(DEV_CONSOLE, 0); // Program must be compiled for TXO!

    //printf("\fReload Group %d", get_group());

    // The first loop attempts to remove all FLASH files in the current group.
    // Our plan is to find the first one, then remove it.  We can repeat this
    // as long as there are any files left, since the "next" file is always
    // the first in this case.  We must make a special case, however: don't
    // remove this program!  (Normally this program will not be in this group.)

    for (; ; ++loop) {
        //
        strcpy(buffer, "F:");
        sts = dir_get_first(buffer);
        if (sts == -1)
            break;
        if (!strcmp(buffer, argv[0])) {
            printf("\nSkip %s", buffer);
            break;
        }
        //printf("\nDel %s",buffer);

        display_at(1, inImamLineNumber, szFlashStatus[Index], CLR_EOL);
        SVC_WAIT(300);
        Index = (++Index >= 4 ? 0 : Index);
        if (remove(buffer) < 0)
            SVC_RESTART(argv[0]);
        /****** /
            if ( (loop % 7) == 0 )
            {
                printf("\fReload Group %d", get_group());
            }
            *****/
    }

    // The next loop is exercised ONLY if we are running from the group which
    // is being cleaned up.  Here we must start looking at the first file which
    // occurs after "myself" in the directory.

    if (sts != -1)  // If we're running from the current group,
        for (; ;) {
            // remove any FLASH file which occurs after "myself"
            strcpy(buffer, argv[0]);
            sts = dir_get_next(buffer);
            if (sts == -1)
                break;

            //printf("\nDel %s",buffer);
            display_at(1, inImamLineNumber, szFlashStatus[Index], CLR_EOL);
            SVC_WAIT(300);
            Index = (++Index >= 4 ? 0 : Index);
            if (remove(buffer) < 0)
                SVC_RESTART(argv[0]);
            /****** /
                if ( (loop % 7) == 0 )
                {
                    printf("\fReload Group %d", get_group());
                }
                *****/
        }

    // Now determine if we can recover enough space to justify a download.
    // We saved the caller's argument in CONFIG.SYS in case of power loss.

    buffer[get_env(arg1, buffer, sizeof(buffer) - 1)] = 0;
    minimum = strtol(buffer, NULL, 10);

    sts = dir_flash_coalesce_size(&recover);
    //printf ("\ndir_flash_coalesce_size = %d", sts);

    if (recover > minimum) {
        //printf("\n%ld > %ld",recover,minimum);
        //printf("\nCoalescing FLASH");
        display_at(1, inImamLineNumber, "Coalescing FLASH", CLR_EOL);
        dir_flash_coalesce();
    }

    //printf("\nAttempting download");  // Here we go!
    //printf("\nSVC_ZONTALK('F')"); // In real program, actually do it

    display_at(1, inImamLineNumber, "Initiating Download", NO_CLEAR);
    SVC_WAIT(2000);
    SVC_ZONTALK('F');
    SVC_RESTART(argv[0]);
    return (0);
}
